package com.xhui.vimarket.common.utils.collection.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xhui.vimarket.common.utils.collection.VimarketList;

public class VimarketArrayList<E> extends ArrayList<E> implements VimarketList<E> {

    /**
     * 默认初始数组的容量大小。
     */
    protected static final int DEFAULT_CAPACITY = 10;
    
    /**
     * 数组容量扩展因子。
     */
    private static final int CAPACITY_EXTEND_FACTOR = 3;

    /**
     * 日志记录器。
     */
    private static final Logger LOG = LoggerFactory.getLogger(VimarketArrayList.class);
    
    /**
     * 版本序列号。
     */
    private static final long serialVersionUID = -5860934859259519404L;
    //    protected boolean isInitialCompleted;
    /**
     * 用于区分存放数组中元素，是初始数据还是新增元素。
     */
    private transient ElementStateFlag[] initialFlags;
//    private transient Object[] additionData;
    /**
     * 用于存放从初始数组中删除的数据。
     */
    private transient Object[] deletionData;
    /**
     * 用于存放从初始数组中更新的数据。
     */
    private transient Object[] updationData;
    /**
     * 初始数据的大小。
     */
    private int initialSize;
    /**
     * 新增数据的大小。
     */
    private int additionSize;
    /**
     * 从初始数据中移除的元素个数。
     */
    private int deletionSize;
    /**
     * 从初始数据中更新的元素个数。
     */
    private int updationSize;
    
    /**
     * 默认构造函数。
     * 
     */
    public VimarketArrayList() {
        this(DEFAULT_CAPACITY);
//        this.isInitialCompleted = true;
    }
    
    /**
     * 根据初始列表大小，构造列表。
     * 
     */
    public VimarketArrayList(int initialCapacity) {
        super(initialCapacity);
        this.initialFlags = new ElementStateFlag[initialCapacity];
        this.deletionData = new Object[initialCapacity];
        this.updationData = new Object[initialCapacity];
//        this.isInitialCompleted = true;
    }
    
    /**
     * 根据初始集合，初始化List。
     * 
     */
    public VimarketArrayList(Collection<? extends E> c) {
        super(c);
        this.initialSize = super.size();
        this.initialFlags = new ElementStateFlag[super.size()];
        Arrays.fill(this.initialFlags, ElementStateFlag.INITIAL);
        this.deletionData = new Object[DEFAULT_CAPACITY];
        this.updationData = new Object[DEFAULT_CAPACITY];
//        this.isInitialCompleted = true;
    }
    
    /**
     */
    @Override
    public void trimToSize() {
        super.trimToSize();
        this.trimToSizeOfDeletionData();
        this.trimToSizeOfUpdationData();
    }
    
    /**
     * 对移除数组移除多余的空元素。
     * 
     */
    protected void trimToSizeOfDeletionData() {
        int oldCapacity = this.deletionData.length;
        if (this.deletionSize < oldCapacity) {
            this.deletionData = Arrays.copyOf(this.deletionData, this.deletionSize);
        }
    }
    
    /**
     * 对更新数组移除多余的空元素。
     * 
     */
    protected void trimToSizeOfUpdationData() {
        int oldCapacity = this.updationData.length;
        if (this.updationSize < oldCapacity) {
            this.updationData = Arrays.copyOf(this.updationData, this.updationSize);
        }
    }

    /**
     * {@inheritDoc}
     * @see java.util.ArrayList#clone()
     */
    @SuppressWarnings("unchecked")
    @Override
    public Object clone() {
    	VimarketArrayList<E> v = (VimarketArrayList<E>) super.clone();
        v.initialFlags = Arrays.copyOf(this.initialFlags, this.size());
        v.deletionData = Arrays.copyOf(this.deletionData, this.deletionSize);
        v.updationData = Arrays.copyOf(this.updationData, this.updationSize);
        v.initialSize = this.initialSize;
        v.additionSize = this.additionSize;
        v.deletionSize = this.deletionSize;
        v.updationSize = this.updationSize;
        return v;
    }

    /**
     * {@inheritDoc}
     * 
     * 从有效数组中移除，并添加为新元素；如果是初始数组元素，则添加到“deletionData”数组，并设置标志位。
     * 
     * @see java.util.ArrayList#set(int, java.lang.Object)
     */
    @Override
    public E set(int index, E element) {
        E oldValue = super.set(index, element);
        if (this.initialFlags[index] != ElementStateFlag.ADDED) { //初始状态
            if (this.initialFlags[index] == ElementStateFlag.UPDATED) {
                int updateIndex = this.getIndexOfUpdationData(oldValue);
                if (updateIndex != -1) {
                    this.removeFromUpdationData(updateIndex);
                }
            }
            this.addToDeletionData(oldValue);
            this.initialFlags[index] = ElementStateFlag.ADDED;
            this.initialSize--;
            this.additionSize++;
        }
        return oldValue;
    }
    
    /**
     * 向“updationData”中添加数据。
     * 
     * @param value 添加信息
     * @return 是否添加成功
     */
    protected boolean addToUpdationData(Object value) {
        this.ensureCapacityOfUpdationData(this.updationSize + 1);
        this.updationData[this.updationSize++] = value;
        return true;
    }
    
    /**
     * 扩展“updationData”的容量大小的最小限度。
     * 
     * @param minCapacity 最小容量大小
     */
    protected void ensureCapacityOfUpdationData(int minCapacity) {
        int oldCapacity = this.updationData.length;
        if (minCapacity > oldCapacity) {
            int newCapacity = (oldCapacity * CAPACITY_EXTEND_FACTOR) / 2 + 1;
            if (newCapacity < minCapacity) {
                newCapacity = minCapacity;
            }
            // minCapacity is usually close to size, so this is a win:
            this.updationData = Arrays.copyOf(this.updationData, newCapacity);
        }
    }
    
    /**
     * 从更新数组中移除元素。
     * 
     * @param index 更新元素的位置
     */
    protected void removeFromUpdationData(int index) {
        //this.rangeCheckOfUpdationData(index);
        //E oldValue = (E) this.updationData[index];
        int numMoved = this.updationSize - index - 1;
        if (numMoved > 0) {
            System.arraycopy(this.updationData, index + 1, this.updationData, index, numMoved);
        }
        this.updationData[--this.updationSize] = null; // Let gc do its work
        //return oldValue;
    }
    
//    protected void rangeCheckOfUpdationData(int index) {
//        if (index >= this.updationSize)
//            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.updationSize);
//    }

    /**
     * 从“updationData”中定位到某个对象，并返回在“updationData”中的位置。
     * 
     * @param o 查找对象
     * @return 返回在“updationData”中的位置
     */
    protected int getIndexOfUpdationData(Object o) {
        if (o == null) {
            for (int i = 0; i < this.updationSize; i++) {
                if (this.updationData[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < this.updationSize; i++) {
                if (o.equals(this.updationData[i])) {
                    return i;
                }
            }
        }
        return -1;
    }
    
    
    
    
    
    
    
    /**
     * 向“deletionData”中添加数据。
     * 
     * @param value 添加信息
     * @return 是否添加成功
     */
    protected boolean addToDeletionData(Object value) {
        this.ensureCapacityOfDeletionData(this.deletionSize + 1);
        this.deletionData[this.deletionSize++] = value;
        return true;
    }
    
    /**
     * 从删除数组中移除元素。
     * 
     * @param index 移除元素的位置
     */
    protected void removeFromDeletionData(int index) {
        //this.rangeCheckOfDeletionData(index);
        //E oldValue = (E) this.deletionData[index];
        int numMoved = this.deletionSize - index - 1;
        if (numMoved > 0) {
            System.arraycopy(this.deletionData, index + 1, this.deletionData, index, numMoved);
        }
        this.deletionData[--this.deletionSize] = null; // Let gc do its work
        //return oldValue;
    }
    
//    protected void rangeCheckOfDeletionData(int index) {
//        if (index >= this.deletionSize)
//            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.deletionSize);
//    }

    /**
     * 从“deletionData”中定位到某个对象，并返回在“deletionData”中的位置。
     * 
     * @param o 查找对象
     * @return 返回在“deletionData”中的位置
     */
    protected int getIndexOfDeletionData(Object o) {
        if (o == null) {
            for (int i = 0; i < this.deletionSize; i++) {
                if (this.deletionData[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < this.deletionSize; i++) {
                if (o.equals(this.deletionData[i])) {
                    return i;
                }
            }
        }
        return -1;
    }
    
    /**
     * 扩展“deletionData”的容量大小的最小限度。
     * 
     * @param minCapacity 最小容量大小
     */
    protected void ensureCapacityOfDeletionData(int minCapacity) {
        int oldCapacity = this.deletionData.length;
        if (minCapacity > oldCapacity) {
            int newCapacity = (oldCapacity * CAPACITY_EXTEND_FACTOR) / 2 + 1;
            if (newCapacity < minCapacity) {
                newCapacity = minCapacity;
            }
            // minCapacity is usually close to size, so this is a win:
            this.deletionData = Arrays.copyOf(this.deletionData, newCapacity);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * 顺序执行以下动作：
     * 1. 判断是否存在于“deletionData”；
     * 2. 如果存在，则从元素从“deletionData”中移到有效数组，并设置标志位ElementStateFlag.UPDATED；
     * 3. 如果不存在，则直接添加到有效数组，并设置标志位ElementStateFlag.ADDED。
     * 
     * @see java.util.ArrayList#add(java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean add(E e) {
        boolean result;
        int iIndex = this.getIndexOfDeletionData(e);
        if (iIndex == -1) {
            result = super.add(e);
            this.addToInitialFlag(ElementStateFlag.ADDED);
            this.additionSize++;
        } else {
            result = super.add((E) this.deletionData[iIndex]);
            this.removeFromDeletionData(iIndex);
            this.addToInitialFlag(ElementStateFlag.UPDATED);
            this.addToUpdationData(e);
            this.initialSize++;
        }
        return result;
    }
    
    /**
     * {@inheritDoc}
     * 
     * 顺序执行以下步骤：
     * 1. 判断是否存在于“deletionData”；
     * 2. 如果存在，则在插入位置的后续元素全部后移，并将元素从“deletionData”移到有效数组的对应位置，并设置标志位ElementStateFlag.UPDATED；
     * 3. 如果不存在，则直接添加到有效数组，并设置标志位ElementStateFlag.ADDED；
     * 
     * @see java.util.ArrayList#add(int, java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    @Override
    public void add(int index, E element) {
        int iIndex = this.getIndexOfDeletionData(element);
        if (iIndex == -1) {
            super.add(index, element);
            this.addToInitialFlag(index, ElementStateFlag.ADDED);
            this.additionSize++;
        } else {
            super.add(index, (E) this.deletionData[iIndex]);
            this.removeFromDeletionData(iIndex);
            this.addToInitialFlag(index, ElementStateFlag.UPDATED);
            this.addToUpdationData(element);
            this.initialSize++;
        }
    }
    
    /**
     * 将状态为“ElementStateFlag.INITIAL”的元素，更新为“ElementStateFlag.UPDATED”状态。
     * 
     * {@inheritDoc}
     * 
     * @see com.xhui.crm.common.util.collection.CrmCollection#update(java.lang.Object)
     */
    public void update(E element) {
        int iIndex = this.indexOf(element);
        if (iIndex != -1) {
            ElementStateFlag flag = this.initialFlags[iIndex];
            if (flag == ElementStateFlag.INITIAL) {
                this.initialFlags[iIndex] = ElementStateFlag.UPDATED;
                this.addToUpdationData(element);
            }
        }
    }
    
    /**
     * 向标志数组添加标志位。
     * 
     * @param value 标识位信息
     */
    protected void addToInitialFlag(ElementStateFlag value) {
        int size = this.size() - 1;
        this.ensureCapacityOfInitialFlags(size + 1);
        this.initialFlags[size] = value;
    }
    
    /**
     * 向标志数组的特定位置添加新标志位。
     * 
     * @param index 添加位置
     * @param element 标志位信息
     */
    protected void addToInitialFlag(int index, ElementStateFlag element) {
        int size = this.size() - 1;
//        if (index > size || index < 0)
//            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        ensureCapacityOfInitialFlags(size + 1);
        System.arraycopy(this.initialFlags, index, this.initialFlags, index + 1, size - index);
        this.initialFlags[index] = element;
    }
    
    /**
     * 从标志数组中移除某个标志位的信息。
     * 
     * @param index 移除位置 
     */
    protected void removeFromInitailFlags(int index) {
        int size = this.size() + 1;
        //boolean oldValue = this.initialFlags[index];
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            System.arraycopy(this.initialFlags, index + 1, this.initialFlags, index, numMoved);
        }
        this.initialFlags[size - 1] = null; // Let gc do its work
        //return oldValue;
    }
    
    /**
     * 扩展“initialFlags”的容量大小的最小限度。
     * 
     * @param minCapacity 最小容量大小 
     */
    protected void ensureCapacityOfInitialFlags(int minCapacity) {
        int oldCapacity = this.initialFlags.length;
        if (minCapacity > oldCapacity) {
            int newCapacity = (oldCapacity * CAPACITY_EXTEND_FACTOR) / 2 + 1;
            if (newCapacity < minCapacity) {
                newCapacity = minCapacity;
            }
            // minCapacity is usually close to size, so this is a win:
            this.initialFlags = Arrays.copyOf(this.initialFlags, newCapacity);
        }
    }
    
    /**
     * {@inheritDoc}
     * 
     * 顺序执行以下步骤：
     * 
     * 1. 将元素从有效数组中删除，并将后续元素全部前移；
     * 2. 判断标识位；
     * 3. 如果不是ElementStateFlag.ADDED，则将元素添加到“deletionMap”；
     * 4. 删除标识位；
     * 
     * @see java.util.ArrayList#remove(int)
     */
    @Override
    public E remove(int index) {
        return removeInternal(index, true);
    }
    
    /**
     * 删除元素，根据标识位判断是否要移动到DeletionData。
     * 
     * @param index 索引位置
     * @param isAddToDeletionData 是否添加到删除数据中
     * @return 删除元素对象
     */
    private E removeInternal(int index, boolean isAddToDeletionData) {
        E oldValue = super.remove(index);
        if (this.initialFlags[index] != ElementStateFlag.ADDED) {
            if (this.initialFlags[index] == ElementStateFlag.UPDATED) {
                int updateIndex = this.getIndexOfUpdationData(oldValue);
                if (updateIndex != -1) {
                    this.removeFromUpdationData(updateIndex);
                }
            }
            if (isAddToDeletionData) {
                this.addToDeletionData(oldValue);
            }
//            this.initialFlags[index] = false;
            this.initialSize--;
        } else {
            this.additionSize--;
        }
        this.removeFromInitailFlags(index);
        return oldValue;
    }
    
    /**
     * {@inheritDoc}
     * @see java.util.ArrayList#remove(java.lang.Object)
     */
    @Override
    public boolean remove(Object o) {
        int iIndex = this.indexOf(o);
        this.remove(iIndex);
        return true;
    }
    
    /**
     * {@inheritDoc}
     * 
     * 顺序执行以下步骤：
     * 1. 将所有标志位非ElementStateFlag.ADDED的元素，添加到“deletionData”；
     * 2. 删除有效数组中的所有元素。
     */
    @Override
    public void removeAll() {
        // DeletionData
        int size = this.size();
        for (int i = 0; i < size; i++) {
            if (this.initialFlags[i] != ElementStateFlag.ADDED) {
                this.addToDeletionData(this.get(i));
//                this.initialFlags[i] = null; //ElementStateFlag.ADDED;
            }
            this.initialFlags[i] = null; //ElementStateFlag.ADDED;
        }
        
        // UpdationData
        size = this.updationSize;
        for (int i = 0; i < size; i++) {
            this.updationData[i] = null;
        }
        this.updationSize = 0;
        
        // InitialData和AdditionData
        super.clear();
        this.initialSize = 0;
        this.additionSize = 0;
    }
    
    /**
     * {@inheritDoc}
     * 
     * 清空所有的数据。
     * 
     * @see java.util.ArrayList#clear()
     */
    @Override
    public void clear() {
        // 删除DeletionData
        Arrays.fill(this.deletionData, 0, this.deletionSize, null);
        this.deletionSize = 0;
        
        // 删除updationData
        Arrays.fill(this.updationData, 0, this.updationSize, null);
        this.updationSize = 0;
        
        // 删除InitialData和AdditionData
        Arrays.fill(this.initialFlags, 0, this.initialFlags.length, null);
        super.clear();
        this.initialSize = 0;
        this.additionSize = 0;
    }
    
    /**
     * {@inheritDoc}
     * @see com.xhui.crm.common.util.collection.CrmList#initialAllData()
     */
    public void initialAllData() {
        // 删除DeletionData
        Arrays.fill(this.deletionData, 0, this.deletionSize, null);
        this.deletionSize = 0;
        
        // 删除updationData
        Arrays.fill(this.updationData, 0, this.updationSize, null);
        this.updationSize = 0;
        
        // 重置标识位为初始标识
        this.initialSize = this.size();
        Arrays.fill(this.initialFlags, 0, this.initialSize, ElementStateFlag.INITIAL);
        this.additionSize = 0;
    }
    
    /**
     * {@inheritDoc}
     * @see com.xhui.crm.common.util.collection.CrmCollection#restoreAllData()
     * @author huangjb
     * 2011-9-23 huangjb
     */
    @SuppressWarnings("unchecked")
    public void restoreAllData() {
        //删除新增的数据
        int size = this.size();
        for (int i = 0; i < size; i++) {
            if (this.initialFlags[i] == ElementStateFlag.ADDED) {
                this.removeDirectly(i);
            }
        }
        //将删除的数据还原
        if (this.deletionData != null) {
            for (int i = 0; i < this.deletionData.length; i++) {
                if (this.deletionData[i] == null) {
                    continue;
                }
                this.addInitial((E)this.deletionData[i]);
            }
        }
        // 删除DeletionData
        Arrays.fill(this.deletionData, 0, this.deletionSize, null);
        this.deletionSize = 0;
        
        // 删除updationData
        Arrays.fill(this.updationData, 0, this.updationSize, null);
        this.updationSize = 0;
//        // 重置标识位为初始标识
//        this.initialSize = this.size();
//        Arrays.fill(this.initialFlags, 0, this.initialSize, ElementStateFlag.INITIAL);
        this.additionSize = 0;
    }
    /**
     * {@inheritDoc}
     * @see java.util.ArrayList#addAll(java.util.Collection)
     */
    @Override
    public boolean addAll(Collection<? extends E> c) {
        boolean result = false;
        Iterator<? extends E> iterator = c.iterator();
        while (iterator.hasNext()) {
            result |= this.add(iterator.next());
        }
        return result;
//        int numNew = c.size();
//        int size = this.size();
//        super.addAll(c);
//        
//        this.ensureCapacityOfInitialFlags(size + numNew);
//        Arrays.fill(this.initialFlags, size, size + numNew, false);
//        
//        Iterator<? extends E> iterator = c.iterator();
//        for (int i = size; iterator.hasNext(); i++) {
//            int iIndex = this.getIndexOfDeletionData(iterator.next());
//            if (iIndex == -1) {
//                this.additionSize++;
//            } else {
//                super.set(i, (E) this.deletionData[iIndex]);
//                this.removeFromDeletionData(iIndex);
//                this.initialFlags[i] = true;
//                this.initialSize++;
//            }
//        }
//        return numNew != 0;
    }
    
    /**
     * {@inheritDoc}
     * @see java.util.ArrayList#addAll(int, java.util.Collection)
     */
    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        int iIndex = index;
        int oldSize = this.size();
        Iterator<? extends E> iterator = c.iterator();
        while (iterator.hasNext()) {
            this.add(iIndex++, iterator.next());
        }
        return (this.size() > oldSize);
//        int numNew = c.size();
//        int size = this.size();
//        int numMoved = size - index;
//        boolean result = super.addAll(c);
//        
//        this.ensureCapacityOfInitialFlags(size + numNew);
//        if (numMoved > 0) {
//            System.arraycopy(this.initialFlags, index, this.initialFlags, index + numNew, numMoved);
//        }
//        Arrays.fill(this.initialFlags, index, index + numNew, false);
//        
//        Iterator<? extends E> iterator = c.iterator();
//        for (int i = index; iterator.hasNext(); i++) {
//            int iIndex = this.getIndexOfDeletionData(iterator.next());
//            if (iIndex == -1) {
//                this.additionSize++;
//            } else {
//                super.set(i, (E) this.deletionData[iIndex]);
//                this.removeFromDeletionData(iIndex);
//                this.initialFlags[i] = true;
//                this.initialSize++;
//            }
//        }
//        return result;
    }

    /**
     * {@inheritDoc}
     * @see java.util.ArrayList#removeRange(int, int)
     */
    @Override
    protected void removeRange(int fromIndex, int toIndex) {
        for (int i = fromIndex; i < toIndex; i++) {
            this.remove(i);
        }
//        int size = this.size();
//        int numMoved = size - toIndex;
//        int newSize = size - (toIndex - fromIndex);
//        
//        for (int i = fromIndex; i < toIndex; i++) {
//            E oldValue = this.get(i);
//            if (this.initialFlags[i]) {
//                this.addToDeletionData(oldValue);
//                this.initialSize--;
//            } else {
//                this.additionSize--;
//            }
//        }
//        
//        System.arraycopy(this.initialFlags, toIndex, this.initialFlags, fromIndex, numMoved);
//        Arrays.fill(this.initialFlags, newSize, size, false);
//        
//        super.removeRange(fromIndex, toIndex);
    }
    
    /**
     * {@inheritDoc}
     * @see com.xhui.crm.common.util.collection.CrmList#getAdds()
     */
    @Override
    public List<E> getAdds() {
        List<E> list = new ArrayList<E>();
        int size = this.size();
        for (int i = 0; i < size; i++) {
            if (this.initialFlags[i] == ElementStateFlag.ADDED) {
                list.add(this.get(i));
            }
        }
        return list;
    }
    
    /**
     * {@inheritDoc}

     */
    @Override
    public Iterator<E> getAddsIterator() {
        return this.getAdds().iterator();
    }
    
    /**
     * {@inheritDoc}
 
     */
    @Override
    public List<E> getAll() {
        return new ArrayList<E>(this);
    }

    /**
     * {@inheritDoc}
 
     */
    @Override
    public Iterator<E> getAllIterator() {
        return this.iterator();
    }

    /**
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<E> getRemoves() {
        this.trimToSizeOfDeletionData();
        return (List<E>) Arrays.asList(this.deletionData);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<E> getRemovesIterator() {
        return this.getRemoves().iterator();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public List<E> getRetains() {
        List<E> list = new ArrayList<E>();
        int size = this.size();
        for (int i = 0; i < size; i++) {
            if (this.initialFlags[i] != ElementStateFlag.ADDED) {
                list.add(this.get(i));
            }
        }
        return list;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<E> getRetainsIterator() {
        return this.getRetains().iterator();
    }
    
    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public List<E> getUpdates() {
        this.trimToSizeOfUpdationData();
        return (List<E>) Arrays.asList(this.updationData);
//        List<E> list = new ArrayList<E>();
//        int size = this.size();
//        for (int i = 0; i < size; i++) {
//            if (this.initialFlags[i] == ElementStateFlag.UPDATED) {
//                list.add(this.get(i));
//            }
//        }
//        return list;
    }
    
    /**
     * {@inheritDoc}
     */
    public Iterator<E> getUpdatesIterator() {
        return this.getUpdates().iterator();
    }
    
    /**
     * {@inheritDoc}
     */
    public List<E> getInitials() {
        List<E> list = new ArrayList<E>();
        int size = this.size();
        for (int i = 0; i < size; i++) {
            if (this.initialFlags[i] == ElementStateFlag.INITIAL) {
                list.add(this.get(i));
            }
        }
        return list;
    }
    
    /**
     * {@inheritDoc}
     */
    public Iterator<E> getInitialsIterator() {
        return this.getInitials().iterator();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean addInitial(E e) {
        boolean result = super.add(e);
        this.addToInitialFlag(ElementStateFlag.INITIAL);
        this.initialSize++;
        return result;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean addInitial(Collection<? extends E> c) {
        int numNew = c.size();
        int size = this.size();
        boolean result = super.addAll(c);
        this.ensureCapacityOfInitialFlags(size + numNew);
        Arrays.fill(this.initialFlags, size, size + numNew, ElementStateFlag.INITIAL);
        this.initialSize += numNew;
        return result;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean removeDirectly(E e) {
        int iIndex = this.indexOf(e);
        this.removeDirectly(iIndex);
        return true;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public E removeDirectly(int index) {
        return removeInternal(index, false);
    }

    @Override
    public List<E> getCollectionByProperty(String propertyName, Object propertyValue) {
        List<E> list = new ArrayList<E>();
        int size = this.size();
        E item;
        Object value;
        for (int i = 0; i < size; i++) {
            item = this.get(i);
            try {
                value = PropertyUtils.getProperty(item, propertyName);
            } catch (Exception e) {
                LOG.info("Not such property “" + propertyName + "” in CrmArrayList.");
//                e.printStackTrace();
                break;
            }
            if (propertyValue == null) {
                if (value == null) {
                    list.add(item);
                }
            } else {
                if (propertyValue.equals(value)) {
                    list.add(item);
                }
            }
        }
        return list;
    }

    @Override
    public E getByProperty(String propertyName, Object propertyValue) {
        int size = this.size();
        E item = null;
        Object value;
        for (int i = 0; i < size; i++) {
            item = this.get(i);
            try {
                value = PropertyUtils.getProperty(item, propertyName);
            } catch (Exception e) {
                LOG.info("Not such property “" + propertyValue + "” in CrmArrayList.");
//                e.printStackTrace();
                break;
            }
            if (propertyValue == null) {
                if (value == null) {
                    return item;
                }
            } else {
                if (propertyValue.equals(value)) {
                    return item;
                }
            }
        }
        return null;
    }
    
}
